import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.util.ArrayList;
import java.util.List;

public class Simulator extends Thread {

	Process            littleguy;
	BufferedReader     stdout;
	BufferedReader     stderr;
	OutputStreamWriter stdin;
	ArrayList<Player>  players;

	int score;

	public Simulator(ArrayList<Player> frobernate){
		this.score = -1;
		// System.out.println("Entering new Simulator" );
		int randomz0r = (int)Math.random()*1000;
		
		List<String> argv = new ArrayList<String>();
		argv.add("sim-cerrano");
		argv.add(String.valueOf(randomz0r));
		
		ProcessBuilder pb = new ProcessBuilder(argv);
		this.players = frobernate;

		try {
			this.littleguy = pb.start();

			this.stdout = new BufferedReader(
					new InputStreamReader(
							this.littleguy.getInputStream()
					)
			);

			this.stderr = new BufferedReader(
					new InputStreamReader(
							this.littleguy.getErrorStream()
					)
			);


			this.stdin = new OutputStreamWriter( this.littleguy.getOutputStream() );

			// System.out.println("Setting up: " + this.littleguy.toString() );

			this.start();
			this.setup();

		} catch (IOException e) {
			System.err.println("Error! I/O error with the Simulator! ( 0x02)");
			System.err.println("    " + e );
		}

		// System.out.println("We've started off sim: " + this.littleguy.toString() );

	}

	public void write( String s ) throws IOException {
		String hax[] = s.split("\n");
		for ( int i = 0; i < hax.length; ++i ) {
			this.stdin.write( hax[i] + "\r\n" );
			this.stdin.flush();
			// System.out.println("< " + hax[i] );
		}
	}

	public void setup() {
		for ( int i = 0; i < this.players.size(); ++i ) {
			try {
				this.write(this.players.get(i).toString());
				this.write(".");
			} catch (IOException e) {
				System.err.println("Error! I/O error with the Simulator! (0x01)");
				System.err.println("    " + e );
			}
		}

		// System.out.println("OK. Player list sent. Starting sim");

		try {
			this.write(".");
		} catch (IOException e) {
			System.err.println("Error! I/O error with the Simulator! (0x03)");
			System.err.println("    " + e );
		}

	}

	public boolean isRunning() {
		try {
			this.littleguy.exitValue();
			return false;
		} catch ( IllegalThreadStateException e ) {
			return true;
		}
	}

	public void purge() {
		// purge logs
		try {
			while ( this.stdout.ready() ) {
				String line = this.stdout.readLine();
				if ( line != null )
					this.parseLine(line);
			}
			while ( this.stderr.ready() ) {
				String line = this.stderr.readLine();
				if ( line != null )
					this.parseLine(line);
			}
		} catch (IOException e) {
			System.err.println("Error! I/O error with the Simulator! (0xB1)");
			System.err.println("    " + e);
		}
	}

	public int blockingScoreRead() throws WTFException {
		while ( this.isRunning() );
		this.purge();
		int exit_value = this.littleguy.exitValue();
		
		// System.out.println("E: " + exit_value + ", " + this.score );
		
		if ( ! ( exit_value == 0 && this.score != 0 ) )
			throw new WTFException();
		
		return this.score;
	}
	
	public int scoreRead() throws WTFException {
		if ( ! this.isRunning() ) {
			this.purge();
			int exit_value = this.littleguy.exitValue();
			
			// System.out.println("E: " + exit_value + ", " + this.score );
			
			if ( ! ( exit_value == 0 && this.score != 0 ) )
				throw new WTFException();
			
			return this.score;
		}
		else
			throw new IllegalThreadStateException("Not dead yet");
	}
	
	protected void parseLine( String line ) {
		int index = line.indexOf(":");
		if ( index >= 0 ) {
			String header = line.substring(0,index);
			String value  = line.substring(index+1);
			try {
				// System.out.println("(int) " + value );
				int sk0re = Integer.parseInt(value.trim());
				// System.out.println("approved");
				
				if ( header.trim().equalsIgnoreCase("score") ) {
					// System.out.println("noed as score");
					this.score = sk0re;
					// System.out.println("and set");
				}// else {
				//	System.out.println("score != " + header );
				//}
			} catch ( NumberFormatException e ) {
				// System.out.println(line);
				// System.out.println("Does not have a second goodness.");
			}
		}
	}
	
	@Override
	public void run() {
		// System.out.println("Simulator no: " + this.littleguy.toString() + " [s]");
		while ( this.isRunning() ) {
			//System.out.println("Waiting for stdin.");
			try {
				String line = this.stdout.readLine();
				if ( line != null ) {
					this.parseLine(line);
				}
			} catch (IOException e) {
				System.err.println("Error! I/O error with the Simulator! (0x00)");
				System.err.println("    " + e);
			}
		}
		// System.out.println("Simulator no: " + this.littleguy.toString() + " [x]");
	}
}
